import React from 'react';
import { Alert } from 'react-native';

import {costTimeWork, dateFormat, isEmpty, getApiName} from './utils/DebugUtils';
import FloatPanelController from './views/FloatPanelController';

let httpRequestLogs = [], webViewLoadLogs = [], normalLogs = [], exceptionLogs = [];

export default class DebugManager {
    
    static debugLogOff = true;
    
    static setDebugLog(isOn) {
        DebugManager.debugLogOff = !isOn;
    }

    static initServerUrlMap(serverUrlMap, currentUrl, changeCallback) {
        DebugManager.currentUrl = currentUrl;
        DebugManager.serverUrlMap = serverUrlMap;
        DebugManager.changeCallback = changeCallback;
        return DebugManager;
    }

    static initDeviceInfo(deviceInfo) {
        DebugManager.DeviceInfo = deviceInfo;
        return DebugManager;
    }

    static initConfigs(config) {
        DebugManager.Configs = config;
        return DebugManager;
    }

    static initJSException(allowedInDevMode = false, customHandler = this.appendExceptionLogs) {
        if (typeof allowedInDevMode !== "boolean" || typeof customHandler !== "function"){
            console.log("setJSExceptionHandler is called with wrong argument types.. first argument should be callback function and second argument is optional should be a boolean");
            console.log("Not setting the JS handler .. please fix setJSExceptionHandler call");
            return DebugManager;
        }
        const allowed = allowedInDevMode ? true : !__DEV__;
        if (allowed) {
            global.ErrorUtils.setGlobalHandler((error, isFatal)=>{
                console.log(error);
                customHandler && customHandler(error, isFatal);
                if(isFatal) {
                    Alert.alert("出现异常,请截图上报",
                        `错误: ${(isFatal) ? 'Fatal:' : ''} ${error?.name} ${error?.message} ${error?.stack}`, [
                            {
                                text: '关闭',
                                onPress: () => {
                                }
                            }
                        ])
                }
            });
            console.error = (message, error) => global.ErrorUtils.reportError(error); // sending console.error so that it can be caught
        } else {
            console.log("Skipping setJSExceptionHandler: Reason: In DEV mode and allowedInDevMode = false");
        }
        require('promise/setimmediate/rejection-tracking').enable({
            allRejections: true,
            onUnhandled: (id, error) => {
                const warning =
                    `Possible Unhandled Promise Rejection (id: ${id}):\n` +`${error?.message}\n` + error?.stack;
                console.warn(warning);
                customHandler && customHandler(error, id);
            },
            onHandled: (id) => {
              const warning =
                `Promise Rejection Handled (id: ${id})\n` +
                'This means you can ignore any previous messages of the form ' +
                `"Possible Unhandled Promise Rejection (id: ${id}):"`;
              console.warn(warning);
            },
          });
        return DebugManager;
    }

    static appendExceptionLogs(error, isFatal) {
        costTimeWork(() => {
            exceptionLogs.unshift({log: `${isFatal}|${error?.name} ${error?.message} ${error?.stack}`, timeStr: dateFormat(new Date(), 'MM月dd日 hh时mm分ss秒S毫秒')});
            if (exceptionLogs.length > 20) normalLogs.splice(10)//若url个数大于100，则删除前20个
        })
    }

    static appendHttpLogs(params, response, parseResult) {//Http请求日志（请求结果过大的数据不保存） parseResult->用于临时解析
        if (DebugManager.debugLogOff || isEmpty(response)) return;
        if (isEmpty(response._bodyText) && isEmpty(parseResult)) {
            let reader = new FileReader();
            reader.addEventListener('loadend', () => this.appendHttpLogs(params, response, reader.result));
            reader.readAsText(response._bodyBlob);
        } else {
            let resultStr = isEmpty(parseResult) ? response._bodyText : parseResult;
            costTimeWork(() => {
                let obj = {
                    url: response.url,
                    method: params.method,
                    apiName: getApiName(response.url),
                    headers: JSON.stringify(params.headers),
                    body: JSON.stringify(params.body),
                    result: resultStr.substr(0, 2000),
                    completed: resultStr.length < 2000,
                    timeStr: dateFormat(new Date(), 'MM月dd日 hh时mm分ss秒S毫秒'),
                };
                httpRequestLogs.unshift(obj);
                if (httpRequestLogs.length > 30) {
                    httpRequestLogs.splice(10);
                }//若日志个数大于30，则删除前10个
            });
        }
    }

    static appendWebViewLogs(loadUrl) {//webView加载Url
        if (DebugManager.debugLogOff) return;
        costTimeWork(() => {
            webViewLoadLogs.unshift({url: loadUrl, timeStr: dateFormat(new Date(), 'MM月dd日 hh时mm分ss秒S毫秒')});
            if (webViewLoadLogs.length > 100) {
                webViewLoadLogs.splice(20);
            }//若url个数大于100，则删除前20个
        });
    }

    static appendLogs(text) {
        if (DebugManager.debugLogOff) return;
        costTimeWork(() => {
            normalLogs.unshift({log: text, timeStr: dateFormat(new Date(), 'MM月dd日 hh时mm分ss秒S毫秒')});
            if (normalLogs.length > 100) normalLogs.splice(20)//若url个数大于100，则删除前20个
        })
    }

    static getHttpLogs() {//获取Http请求日志列表
        return httpRequestLogs;
    }

    static clearHttpLogs() {//清除Http请求日志列表
        httpRequestLogs = [];
    }

    static getWebLoadLogs() {//获取webView加载日志列表
        return webViewLoadLogs;
    }

    static getLogText() {//获取其它日志列表
        return normalLogs;
    }

    static getExceptionLogText() {
        return exceptionLogs;
    }

    static destroy() {
        httpRequestLogs = [];
        webViewLoadLogs = [];
        normalLogs = [];
    }

    static showFloat(RootSiblings) { // type of  RootSiblings (3.x)
        if (this.sibling) {
            this.sibling.update(<FloatPanelController close={() => this.sibling.destroy()}/>)
        } else {
            this.sibling = new RootSiblings(<FloatPanelController close={() => this.sibling.destroy()}/>);
        }
    }
}
